import { _decorator, Component, Node, Prefab, Vec3, instantiate, director, RigidBody, Enum, CCFloat } from 'cc';

import { poolManager } from '../../../../../Framework/Scripts/Managers/poolManager';
import { ResMgr } from '../../../../../Framework/Scripts/Managers/ResMgr';
import { SoundMgr } from '../../../../../Framework/Scripts/Managers/SoundMgr';
import myUtil from '../../../../../Framework/Scripts/Utils/myUtil';
import { constant, OBJ_TYPE } from '../../../constant';
import { GameApp } from '../../../GameApp';
import { enemyBase } from '../../enemyBase';
import { Bullet } from './Bullet';

import { ProjectileMath } from './ProjectileMath';
// import { TrajectoryDrawer } from './TrajectoryDrawer';
import { VectorUtil } from './utils/VectorUtil';

const { ccclass, property } = _decorator;


/**
 * 模式
 */
enum Mode {
    /** 固定角度和速度 */
    FIXED_ALL = 1,
    /** 固定俯仰角 */
    FIXED_PITCH_ANGLE = 2,
    /** 固定速度 */
    FIXED_VELOCITY = 3,
    /** 不固定角度和速度 */
    UNFIXED = 4,
}

/**
 * 大炮
 */
@ccclass('Cannon')
export class Cannon extends enemyBase {

    

    @property({ type: CCFloat, displayName: "攻击半径" })
    private attackFanwei: number = 10

    @property({ type: CCFloat, displayName: "限制距离" })
    private attackFanwei_min: number = 10
    @property({ type: Node, displayName: '偏航轴节点', group: { name: '自身节点引用', id: '1' } })
    protected yawAxis: Node = null;

    @property({ type: Node, displayName: '俯仰轴节点', group: { name: '自身节点引用', id: '1' } })
    protected pitchAxis: Node = null;

    @property({ type: Node, displayName: '炮弹发射点节点', group: { name: '自身节点引用', id: '1' } })
    protected firePoint: Node = null;

    @property({ type: [Prefab], displayName: '炮弹预制体', group: { name: '炮弹', id: '2' } })
    protected bulletPrefab: Prefab[] =[];

    @property({ type: Enum(Mode), displayName: '模式', group: { name: '模式', id: '3' } })
    public mode: Mode = Mode.FIXED_ALL;

    @property({ displayName: '炮管的俯仰角', visible() { return (this.mode === Mode.FIXED_PITCH_ANGLE || this.mode === Mode.FIXED_ALL); }, group: { name: '模式', id: '3' } })
    public fixedPitchAngle: number = -45;

    @property({ displayName: '炮弹的初速度', visible() { return (this.mode === Mode.FIXED_VELOCITY || this.mode === Mode.FIXED_ALL); }, group: { name: '模式', id: '3' } })
    public fixedVelocity: number = 5;

    @property({ displayName: '使用小俯仰角', visible() { return (this.mode === Mode.FIXED_VELOCITY); }, group: { name: '模式', id: '3' } })
    public useSmallPitchAngle: boolean = false;

    private BulletIndex:number=0
    /**
     * 速度
     */
    private velocity: number = 0;
    private itemTarget: Node[] = null


    // 旋转精度阈值
    private rotationThreshold: number = 1; // 以度为单位

    // 目标旋转的俯仰和偏航角
    private targetPitch: number = 0;
    private targetYaw: number = 0;

    // 插值速度因子
    private rotationLerpFactor: number = 0.1;

    private time: number = 0

    /**
     * 俯仰角
     */


    private get pitch() {
        return this.pitchAxis.eulerAngles.x;
    }
    private set pitch(value: number) {

        // this.pitchAxis.setRotationFromEuler(value, 0, 0);
    }

    /**
     * 偏航角
     */
    private get yaw() {
        return this.yawAxis.eulerAngles.y;
    }
    private set yaw(value: number) {
        // this.yawAxis.setRotationFromEuler(0, value, 0);
    }

    /**
     * 大炮的世界坐标
     */
    private get mainPosition() {
        return this.yawAxis.getWorldPosition();
    }

    /**
     * 大炮的正前方向向量（+z）
     */
    private get mainForward() {
        return this.yawAxis.parent.forward.negative();
    }

    /**
     * 大炮的正上方向向量（+y）
     */
    private get mainUp() {
        return this.yawAxis.up;
    }
    /**
     * 模式
     */
    private static get Mode() {
        return Mode;
    }
    private isRot: boolean = false
    /**
     * 当前瞄准的目标位置
     */
    private curTargetPos: Vec3 = new Vec3(0, -2, 2);


    private targetPos: Vec3 = new Vec3()

    //找敌人
    public findEnemy(): Node {

        var nodeArr = []
        //  const enemyArr = this.enemy_root.children

        for (let i = 0; i < this.itemTarget.length; i++) {
            const len: number = myUtil.getTwoNodeXZLengthSqr(this.itemTarget[i], this.node)

            if (len <= this.attackFanwei && len >= this.attackFanwei_min) {
                nodeArr.push(this.itemTarget[i])

            }
        }


        return this.getNearestMonster(nodeArr)
    }


    /**
     * 获取距离最近的小怪、boss节点
     * @returns 
     */
    public getNearestMonster(enemyArr: Node[]) {


        if (enemyArr.length) {
            let arr = enemyArr.sort((a: any, b: any) => {
                let distanceA = myUtil.getTwoNodeXZLengthSqr(this.node, a);
                let distanceB = myUtil.getTwoNodeXZLengthSqr(this.node, b);
                return distanceA - distanceB;
            })

            arr = arr.filter((item: Node) => {
                let ts: enemyBase = null

                ts = item.getComponent(enemyBase);



                return item.parent !== null && ts && !ts.isDie
            })

            return arr[0];
        } else {
            return null;
        }
    }

    init() {
         const attackLevel:number=constant.buildData.cannonAttack.level
         if(attackLevel<=3){
             this.BulletIndex=0
             this.node.setScale(1.5,1.5,1.5)
         }else if(attackLevel<=6){
             this.BulletIndex=1
             this.node.setScale(2,2,2)
         }else{
            this.node.setScale(2.5,2.5,2.5)
             this.BulletIndex=2
         }
     
        this.attackFanwei= this.attackFanwei+( this.attackFanwei*constant.buildData.cannonRange.add*constant.buildData.cannonRange.level)


        this.attackFanwei *= this.attackFanwei//转换平方
        this.attackFanwei_min *= this.attackFanwei_min

        this.obj_type = OBJ_TYPE.friendly//防御固定是友军
        this.itemTarget = GameApp.Instance.enemyRoot.children


       
   
        this.schedule(() => {
            if (this.itemTarget.length > 0) {
                const n: Node = this.findEnemy()
                if (n) {
                    this.isRot = true

                    this.targetPos = n.getWorldPosition()
                    this.aim(this.targetPos)
                }

            }

        }, 3)
    }
    onLoad() {
   
     
        

        this.init()
    }


    /**
     * 瞄准
     * @param targetPos 目标位置
     */
    private aim(targetPos: Vec3) {
        if (targetPos.x == 0) {
            targetPos.x = 0.00001
        }
        // 保存另作他用
        this.curTargetPos.set(targetPos);

        // 偏航角（Yaw）
        // 大炮直接看向目标点的方向矢量
        const direction = Vec3.subtract(new Vec3, targetPos, this.mainPosition);
        // 计算方向矢量和大炮的向前矢量之间的夹角（有符号）
        const yawAngle = -VectorUtil.signedAngle(direction, this.mainForward, this.mainUp);

        // 俯仰角（Pitch）和速度
        let pitchAngle = NaN
        let velocity = NaN;
        //   let fixedTrajectoryDistance = false;
        const result = this.calculateWithMaxHeight(targetPos);
        pitchAngle = -result.angle;
        velocity = result.velocity;
        this.time = result.time//传入炮弹


        // 角度值是否有效
        if (isNaN(pitchAngle)) {
            pitchAngle = this.pitch;    // 维持当前角度
        }
   


        // 记录速度
        if (!isNaN(velocity)) {
            this.velocity = velocity;
        }



        // 更新目标旋转角度而不是直接旋转
        this.targetPitch = pitchAngle;//有误  Y仰角
        this.targetYaw = yawAngle;




    }


    /**
     * 发射
     * @param velocity 初始速度
     */
    private shoot(velocity: number) {
        // 获取炮弹
        const bulletNode = this.generateBullet(),
            bulletRigidBody = bulletNode.getComponent(RigidBody);
        // 方向和速度（默认前方为 -z 方向，需要反过来）
        const direction = bulletNode.forward.negative();
        direction.multiplyScalar(velocity);
        // 给刚体设置速度
        bulletRigidBody.setLinearVelocity(direction);
        const ts: Bullet = bulletNode.getComponent(Bullet)
        if (ts) {

            SoundMgr.Instance.playSound(ResMgr.Instance.getAsset("Sounds","fireBall"))
            ts.init(this.node,this.targetPos)
        }
    }



    /**
     * 生成炮弹
     */
    private generateBullet() {
       
        const node =poolManager.instance.getNode(this.bulletPrefab[this.BulletIndex],this.node) 

      
        
       
        node.setWorldPosition(this.firePoint.getWorldPosition());
        node.setWorldRotation(this.firePoint.getWorldRotation());
        return node;
    }

    /**
     * 计算位移距离
     * @param targetPos 目标位置
     */
    private calculateDisplacement(targetPos: Vec3) {
        // 从目标点到发射点的方向矢量
        const firePos = this.firePoint.getWorldPosition(),
            direction = Vec3.subtract(new Vec3, targetPos, firePos);
        // 垂直位移（相当于 targetPos.y - firePos.y）
        const vertical = direction.y;
        // 水平位移（将方向矢量投影到水平面上，其长度就是水平位移的长度）
        const horizontal = VectorUtil.projectOnPlane(direction, Vec3.UP).length();
        return { horizontal, vertical };
    }





    /**
     * 根据最大高度计算速度和角度
     * @param targetPos 目标位置
     */
    private calculateWithMaxHeight(targetPos: Vec3) {
        const { horizontal, vertical } = this.calculateDisplacement(targetPos);
        const maxHeight = Math.max(0.5, vertical + (horizontal * 0.3));  // 最大高度
        return ProjectileMath.calculateWithMaxHeight(horizontal, vertical, maxHeight);
    }
    update(dt: number) {


        if (!this.isRot) {
            return
        }
  
        // 检查旋转是否足够接近目标


        const p: number = Math.abs(this.pitch - this.targetPitch)
        const y: number = Math.abs(this.yaw - this.targetYaw)
        const currentPitch = this.pitch;
        const currentYaw = this.yaw;


        if (p <= this.rotationThreshold &&
            y <= this.rotationThreshold) {
            //    console.log("开炮");



            this.pitchAxis.setRotationFromEuler(this.targetPitch, 0, 0);
            this.yawAxis.setRotationFromEuler(0, this.targetYaw, 0);

            this.isRot = false
            this.shoot(this.velocity)
         //   this.fire()

            // 绘制弹道

        } else {
            // 插值旋转以平滑地朝向目标



            const newPitch = currentPitch + (this.targetPitch - currentPitch) * this.rotationLerpFactor;
            const newYaw = currentYaw + (this.targetYaw - currentYaw) * this.rotationLerpFactor;

            this.pitchAxis.setRotationFromEuler(newPitch, 0, 0);
            this.yawAxis.setRotationFromEuler(0, newYaw, 0);
       
        }

    }
}
